/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tencent.tendon.convert.json;

import com.tencent.tendon.convert.json.streams.*;
import com.tencent.tendon.convert.util.Utility;
import java.lang.reflect.Type;

/**
 * 对外的使用类
 *
 * @author nbzhang
 */
@SuppressWarnings("unchecked")
public final class JsonConvert {

    private JsonConvert() {
    }

    public static String convertTo(Object value) {
        if (value == null) return "null";
        final JsonDefaultWriter out = JsonPool.pollJsonDefaultWriter();
        JsonAnyEncoder.getInstance().convertTo(out, value);
        String result = out.toString();
        JsonPool.offer(out);
        return result;
    }

    public static byte[] convertToUTF8Bytes(Object value) {
        if (value == null) return new byte[]{110, 117, 108, 108};
        final JsonDefaultWriter out = JsonPool.pollJsonDefaultWriter();
        JsonAnyEncoder.getInstance().convertTo(out, value);
        byte[] result = out.toUTF8Bytes();
        JsonPool.offer(out);
        return result;
    }

    public static void convertTo(Object value, Appendable out) {
        if (out == null) throw new NullPointerException();
        JsonWriter writer = new JsonStreamWriter(out);
        if (value == null) {
            writer.writeNull();
        } else {
            JsonAnyEncoder.getInstance().convertTo(writer, value);
        }
        writer.release();
    }

    public static <T> T convertFrom(String text, Type clazz) {
        return convertFrom(text, null, clazz);
    }

    public static <T> T convertFrom(String text, String key, Type clazz) {
        JsonDefaultReader reader = JsonPool.pollJsonDefaultReader();
        reader.text(text);
        return convertFrom(reader, key, clazz);
    }

    public static <T> T convertFrom(char[] text, Type clazz) {
        return convertFrom(text, null, clazz);
    }

    public static <T> T convertFrom(char[] text, String key, Type clazz) {
        JsonDefaultReader reader = JsonPool.pollJsonDefaultReader();
        reader.text(text);
        return convertFrom(reader, key, clazz);
    }

    public static <T> T convertFrom(char[] text, int start, int len, Type clazz) {
        return convertFrom(text, start, len, null, clazz);
    }

    public static <T> T convertFrom(char[] text, int start, int len, String key, Type clazz) {
        JsonDefaultReader reader = JsonPool.pollJsonDefaultReader();
        reader.text(text, start, len);
        return convertFrom(reader, key, clazz);
    }

    public static <T> T convertFrom(byte[] utf8bytes, Type clazz) {
        return convertFrom(utf8bytes, null, clazz);
    }

    public static <T> T convertFrom(byte[] utf8bytes, String key, Type clazz) {
        return convertFrom(utf8bytes, 0, utf8bytes.length, key, clazz);
    }

    public static <T> T convertFrom(byte[] utf8bytes, int start, int len, Type clazz) {
        return convertFrom(utf8bytes, start, len, null, clazz);
    }

    public static <T> T convertFrom(byte[] utf8bytes, int start, int len, String key, Type clazz) {
        return convertFrom(Utility.decodeUTF8(utf8bytes, start, len), key, clazz);
    }

    public static <T> T convertFrom(Readable src, Type clazz) {
        return convertFrom(src, null, clazz);
    }

    public static <T> T convertFrom(Readable src, String key, Type clazz) {
        JsonReader reader = new JsonStreamReader(src);
        return convertFrom(reader, key, clazz);
    }

    public static <T> T[] convertArrayFrom(String text, Type clazz) {
        return convertArrayFrom(text, null, clazz);
    }

    public static <T> T[] convertArrayFrom(String text, String key, Type clazz) {
        JsonDefaultReader reader = JsonPool.pollJsonDefaultReader();
        reader.text(text);
        return convertArrayFrom(reader, key, clazz);
    }

    public static <T> T[] convertArrayFrom(char[] text, Type clazz) {
        return convertArrayFrom(text, null, clazz);
    }

    public static <T> T[] convertArrayFrom(char[] text, String key, Type clazz) {
        JsonDefaultReader reader = JsonPool.pollJsonDefaultReader();
        reader.text(text);
        return convertArrayFrom(reader, key, clazz);
    }

    public static <T> T[] convertArrayFrom(char[] text, int start, int len, Type clazz) {
        return convertArrayFrom(text, start, len, null, clazz);
    }

    public static <T> T[] convertArrayFrom(char[] text, int start, int len, String key, Type clazz) {
        JsonDefaultReader reader = JsonPool.pollJsonDefaultReader();
        reader.text(text, start, len);
        return convertArrayFrom(reader, key, clazz);
    }

    public static <T> T[] convertArrayFrom(byte[] utf8bytes, Type clazz) {
        return convertArrayFrom(utf8bytes, null, clazz);
    }

    public static <T> T[] convertArrayFrom(byte[] utf8bytes, String key, Type clazz) {
        return convertArrayFrom(Utility.decodeUTF8(utf8bytes), key, clazz);
    }

    public static <T> T[] convertArrayFrom(byte[] utf8bytes, int start, int len, Type clazz) {
        return convertArrayFrom(utf8bytes, start, len, null, clazz);
    }

    public static <T> T[] convertArrayFrom(byte[] utf8bytes, int start, int len, String key, Type clazz) {
        return convertArrayFrom(Utility.decodeUTF8(utf8bytes, start, len), key, clazz);
    }

    public static <T> T[] convertArrayFrom(Readable src, Type clazz) {
        return convertArrayFrom(new JsonStreamReader(src), null, clazz);
    }

    public static <T> T[] convertArrayFrom(Readable src, String key, Type clazz) {
        return convertArrayFrom(new JsonStreamReader(src), key, clazz);
    }

    private static <T> T convertFrom(final JsonReader reader, String key, final Type clazz) {
        if (key != null) reader.seek(key);
        JsonDecodable<T> token = JsonFactory.findDecoder(clazz);
        if (token == null) token = JsonFactory.findListener(clazz);
        if (token == null) {
            if ((clazz instanceof Class) && ((Class) clazz).isArray()) {
                return (T) convertArrayFrom(reader, key, ((Class) clazz).getComponentType());
            }
            token = JsonFactory.loadDecoder(clazz);
        }
        T result = token.convertFrom(reader);
        reader.close();
        return result;
    }

    private static <T> T[] convertArrayFrom(final JsonReader reader, String key, final Type clazz) {
        if (key != null) reader.seek(key);
        JsonDecodable<T> decoder = JsonFactory.findListener(clazz);
        if (decoder == null) decoder = JsonFactory.loadDecoder(clazz);
        final JsonDecoder<T[]> decoders = JsonArrayDecoder.create(clazz, decoder);
        T[] result = decoders.convertFrom(reader);
        reader.close();
        return result;
    }
}
